/**
 * 
 */
package cn.edu.ustc.multicore.exercise.ch5;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import cn.edu.ustc.multicore.exercise.ch1.PrimeSearching;

/**
 * @author dragon
 * 
 */
public class ShareBathroom {
	Toothpaste toothpaste;
	Lock lock = null;
	Condition condition;
	int female;
	int male;

	public ShareBathroom() {
		toothpaste = new Gaolujie();
		female = 0;
		male = 0;
		lock = new ReentrantLock();
		condition = lock.newCondition();

	}

	public void enterMale(long id) {
		System.out.println("A man:"+id+" arrvied...");
		lock.lock();
		try {
			// bathroom occupied by female
			while (female > 0) {
				try {
					condition.await();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			male++;
			System.out.println("A man:"+id+" entered bathroom");
		} finally {
			lock.unlock();
		}
	}

	public void leaveMale(long id) {
		lock.lock();
		try {
			male--;
			System.out.println("A man:"+id+" left");
			// active waiting female
			if (male == 0)
				condition.signalAll();
		} finally {
			lock.unlock();
		}
	}

	public void enterFemale(long id) {
		System.out.println("A woman:"+id+" arrvied...");
		lock.lock();
		try {
			// bathroom occupied by male
			while (male > 0) {
				try {
					condition.await();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			female++;
			System.out.println("A woman:"+id+" entered bathroom");
		} finally {
			lock.unlock();
		}
	}

	public void leaveFemale(long id) {
		lock.lock();
		try {
			female--;
			System.out.println("A woman:"+id+" left");
			// active waiting male
			if (female == 0)
				condition.signalAll();
		} finally {
			lock.unlock();
		}
	}
	private  interface Toothpaste{
		public double getPrice();
		public int getVolume();
		public String getName();
	}
	private static class Gaolujie implements Toothpaste{
		int volume = 0;
		double price = 0;
		String name; 
		public Gaolujie(){
			//300 ml
			volume = 100;
			price = 5.6;
			name ="Gaolujie";
		}
		public double getPrice() {
			return price;
		}
		public int getVolume() {
			return volume;
		}
		public String getName() {
			return name;
		}
	}
	private static class Teeth{
		
		public void brush(Man man, Toothpaste toothpaste){
			//TODO
			System.out.println("the person with id:"+man.getId()+" brush teeth with "+ toothpaste.getName());
		}
	}
	private static interface Man {
		public long getId();
	};
	private static class Male extends Thread implements Man{
		private ShareBathroom bathroom;
		private Teeth teeth;
		private long id;
		
		public Male(ShareBathroom bathroom){
			this.bathroom = bathroom;
			this.teeth = new Teeth();
		}
		public void run() {
			id = this.getId();
			bathroom.enterMale(id);
			//brush teeth
			teeth.brush(this,bathroom.toothpaste);
			bathroom.leaveMale(id);
			
		}
	}

	private static class Female extends Thread implements Man{
		private ShareBathroom bathroom;
		private Teeth teeth;
		private long id;
		public Female(ShareBathroom bathroom){			
			this.bathroom = bathroom;
			this.teeth = new Teeth();
		}
		public void run() {
			id = this.getId();
			bathroom.enterFemale(id);
			//brush teeth
			teeth.brush(this,bathroom.toothpaste);
			bathroom.leaveFemale(id);
		}
	}

	enum Gander {
		MALE, FEMALE;
	}

	public static void main(String[] args) {
		int customers = 10;
		// parse the parameter, and assign them
		if (args != null & args.length > 0) {
			boolean correct = true;
			for (int i = 0; i < args.length; i++) {
				if ("-customers".equals(args[i])) {
					if (args[i + 1] != null) {
						customers = Integer.valueOf(args[i + 1]);
						i++;
						continue;
					} else {
						correct = false;
						break;
					}
				}
				if (!correct) {
					System.out.println("Usage: "
							+ PrimeSearching.class.getName()
							+ " -threads number");
					return;
				}
			}
		}
		
		Gander[] ganders = new Gander[] { Gander.MALE, Gander.FEMALE };
		Thread[] users = new Thread[customers];
		
		ShareBathroom bathroom = new ShareBathroom();
		// generate customer randomly
		for (int i = 0; i < customers; i++) {
			int index = (int) Math.round(Math.random() * 1);
			if (ganders[index] == Gander.MALE) {
				users[i] = new Male(bathroom);
			} else {
				users[i] = new Female(bathroom);
			}
			users[i].start();
		}

	}
}
